#! /bin/bash
#
# This file is part of DisOrder
# Copyright (C) 2008 Richard Kettlewell
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

set -e

while [ $# -gt 0 ]; do
  opt="$1"
  shift
  case "$opt" in
  -h | --help )
    cat  <<EOF

Usage:
  scripts/setup [OPTIONS]

Options:
  --root ROOT             Add a root (can be used multiple times)
  --encoding ENCODING     Filename encoding
  --port PORT             TCP port to listen on or 'none'
  --smtp-server HOSTNAME  SMTP server
  --email ADDRESS         Origin email address
  --register y|n          Enable/disable online registration
  --play local|network    Choose local or network play
  --mcast ADDRESS PORT    Set multicast address and port for --play network
  -h, --help              Display this message

Sets up a basic DisOrder installation.  You must have run 'make install'
first.  Use scripts/teardown to stop the server and deconfigure.

EOF
    exit 0
    ;;
  --version | -V )
    echo "DisOrder scripts/setup _version_"
    exit 0
    ;;
  --root )
    roots="$roots $1"
    shift
    ;;
  --encoding )
    encoding="$1"
    shift
    ;;
  --port )
    port="$1"
    shift
    ;;
  --smtp-server )
    smtp_server="$1"
    shift
    ;;
  --email )
    mail_sender="$1"
    shift
    ;;
  --register )
    register="$1"
    shift
    ;;
  --play )
    play="$1"
    shift
    ;;
  --mcast )
    play=network
    mcast_address="$1"
    shift
    mcast_port="$1"
    shift
    ;;
  * )
    echo >&2 "ERROR: unknown option '$opt'"
    exit 1
    ;;
  esac
done

echo
echo ------------------------------------------------------------------------
echo "DisOrder setup script"

case $(uname -s) in
Darwin )
  echo "Mac OS X detected"
  os=Mac
  user=jukebox
  group=jukebox
  ;;
FreeBSD )
  echo "FreeBSD detected"
  os=FreeBSD
  user=jukebox
  group=jukebox
  ;;
Linux )
  if grep Debian /etc/issue >/dev/null 2>&1; then
    echo "You appear to be running Debian - please use .debs instead"
    echo
  elif grep Ubuntu /etc/issue >/dev/null 2>&1; then
    echo "You appear to be running Ubuntu - please use .debs instead"
    echo
  fi
  echo "Linux detected"
  os=Linux
  user=jukebox
  group=jukebox
  ;;
* )
  echo 
  echo "WARNING: unknown operating system '$(uname -s)'"
  echo "This script won't be able to do all setup on this platform"
  os=unknown
  user=daemon
  group=daemon
  ;;
esac

echo
echo "This script will:"
echo " - overwrite any existing configuration"
echo " - set the server up to be run at boot time"
echo " - start the server"
echo " - set up the web interface"
echo
echo "If this is not what you want, press ^C."
echo ------------------------------------------------------------------------

if [ -z "$roots" ]; then
  while :; do
    echo
    echo "What directory or directories contain your music files:"
    echo "(enter one or more directories separated by spaces)"
    read -r roots
    ok=true
    anyroots=false
    for root in $roots; do
      if [ ! -d $root ]; then
	echo "'$root' does not exist"
	ok=false
      else
        anyroots=true
      fi
    done
    if $anyroots && $ok; then
      break
    fi
  done
fi

if [ -z "$encoding" ]; then
  while :; do
    echo 
    echo "What filesystem encoding should I assume for track names?"
    echo "(e.g. UTF-8, ISO-8859-1, ...)"
    read -r encoding
    if [ ! -z "$encoding" ]; then
      break
    fi
  done
fi

if [ -z "$port" ]; then
  while :; do
    echo
    echo "What TCP port should DisOrder listen on?"
    echo "(enter 'none' for none)"
    read -r port
    case $port in
    none )
      break
      ;;
    [^0-9] | "" )
      echo "'$port' is not a valid port number"
      continue
      ;;
    * )
      break
      ;;
    esac
  done
fi

if [ -z "$play" ]; then
  while :; do
    echo
    echo "How do you want to play sound?  Enter 'local' to use a local sound"
    echo "device or 'network' to multicast sound across your network."
    read -r play
    case $play in
    'local' | network )
      break
      ;;
    * )
      echo "Enter 'local' or 'network'"
      continue
      ;;
    esac
  done
fi

if [ "x$play" = xnetwork ]; then
  if [ -z "$mcast_address" ]; then
    echo
    echo "Enter destination address for network transmission"
    echo "(e.g. a multicast address)"
    read -r mcast_address
  fi
  if [ -z "$mcast_port" ]; then
    while :; do
      echo
      echo "Enter destination port for network transmission"
      read -r mcast_port
      case $mcast_port in
      none )
	break
	;;
      [^0-9] | "" )
	echo "'$mcast_port' is not a valid port number"
	continue
	;;
      * )
	break
	;;
      esac
    done
  fi
fi

if [ -z "$mail_sender" ]; then
  while :; do
    echo
    echo "What address should mail from DisOrder come from?"
    read -r mail_sender
    case "$mail_sender" in
    *@* )
      break
      ;;
    * )
      echo "Email address must contain an '@' sign"
      ;;
    esac
  done
fi

if [ -z "$register" ]; then
  while :; do
    echo
    echo "Do you want to enable online registration?  (Enter 'y' or 'n')"
    read -r register
    case $register in
    y | n )
      break
      ;;
    esac
  done
fi

echo
echo "Proposed DisOrder setup:"
echo " Music directory:       $roots"
if [ "$port" = none ]; then
  echo " Do not listen on a TCP port"
else
  echo " TCP port to listen on: $port"
fi
if [ ! -z "$smtp_server" ]; then
  echo " SMTP Server:           $smtp_server"
fi
echo " Sender address:        $mail_sender"
echo " Online registration:   $register"
if [ $play = network ]; then
  echo " Send sound to:         $mcast_address port $mcast_port"
fi

echo "Is this OK?  (Enter 'y' or 'n')"
read -r ok
case $ok in
y )
  ;;
* )
  echo
  echo "OK, didn't change anything."
  exit 0
  ;;
esac

mkdir -p pkgconfdir

rm -f pkgconfdir/config.new
for root in $roots; do
  echo "collection fs $encoding $root" >> pkgconfdir/config.new
done
for scratch in slap.ogg scratch.ogg; do
  echo "scratch pkgdatadir/$scratch" >> pkgconfdir/config.new
done
echo "user $user" >> pkgconfdir/config.new
if [ $port != none ]; then
  echo "listen 0.0.0.0 $port" >> pkgconfdir/config.new
fi
if [ $play = network ]; then
  echo "broadcast $mcast_address $mcast_port" >> pkgconfdir/config.new
fi
if [ ! -z "$smtp_server" ]; then
  echo "smtp_server $smtp_server" >> pkgconfdir/config.new
fi
echo "mail_sender $mail_sender" >> pkgconfdir/config.new

echo
echo "Proposed pkgconfdir/config:"
sed < pkgconfdir/config.new 's/^/  /'
echo
echo "Is this OK?  (Enter 'y' or 'n')"
read -r ok
case $ok in
y )
  ;;
* )
  echo
  echo "OK, not installing it."
  rm -f pkgconfdir/config.new
  exit 0
  ;;
esac
echo
echo "Installing pkgconfdir/config"
mv pkgconfdir/config.new pkgconfdir/config

if [ ! -f pkgconfdir/options.user ]; then
  echo "Making sure pkgconfdir/options.user exists"
  touch pkgconfdir/options.user
fi

# pick ID1 ID2 ... IDn
# Echoes an ID matching none of ID1..IDn
pick() {
  local n
  n=250				# better not choose 0!
  while :; do
    ok=true
    for k in "$@"; do
      if [ $n = $k ]; then
        ok=false
        break
      fi
    done
    if $ok; then
      echo $n
      return
    fi
    n=$((1+$n))
  done
}

case $os in
Mac )
  # Apple don't seem to believe in creating a user as a discrete operation
  if dscl . -read /Groups/$group >/dev/null 2>&1; then
    echo "$group group already exists"
  else
    echo "Creating $group group"
    gids=$(dscl . -list /Groups PrimaryGroupID|awk '{print $2}')
    gid=$(pick $gids)
    echo "(picked gid $gid)"
    dscl . -create /Groups/$group
    dscl . -create /Groups/$group PrimaryGroupID $gid
    dscl . -create /Groups/$group Password \*
  fi
  if dscl . -read /Users/$user >/dev/null 2>&1; then
    echo "$user user already exists"
  else
    echo "Creating $user user"
    uids=$(dscl . -list /Users UniqueID|awk '{print $2}')
    uid=$(pick $uids)
    echo "(picked uid $uid)"
    gid=$(dscl . -read /Groups/$group PrimaryGroupID | awk '{print $2}')
    dscl . -create /Users/$user
    dscl . -create /Users/$user UniqueID $uid
    dscl . -create /Users/$user UserShell /usr/bin/false
    dscl . -create /Users/$user RealName 'DisOrder server'
    dscl . -create /Users/$user NFSHomeDirectory pkgstatedir
    dscl . -create /Users/$user PrimaryGroupID $gid
    dscl . -create /Users/$user Password \*
  fi
  ;;
FreeBSD )
  # FreeBSD has a simple well-documented interface
  if pw groupshow $group >/dev/null 2>&1; then
    echo "$group group already exists"
  else
    echo "Creating $group group"
    pw groupadd $group
  fi
  if pw usershow $user >/dev/null 2>&1; then
    echo "$user user already exists"
  else
    echo "Creating $user user"
    pw useradd $user -w no -d pkgstatedir -g $group -c 'DisOrder user'
  fi
  ;;
Linux )
  if grep ^$group: /etc/group >/dev/null; then
    echo "$group group already exists"
  else
    echo "Creating $group group"
    groupadd $group
  fi
  if grep ^$user: /etc/passwd >/dev/null; then
    echo "$user user already exists"
  else
    echo "Creating $user user"
    useradd -d pkgstatedir -g $group $user -c 'DisOrder user'
  fi
  ;;
esac

echo "Making sure that pkgstatedir exists"
mkdir -p pkgstatedir
chown $user:$group pkgstatedir
chmod 2755 pkgstatedir

case $os in
Mac )
  echo "Installing the plist into /Library/LaunchDaemons"
  cp examples/uk.org.greenend.rjk.disorder.plist /Library/LaunchDaemons/.
  echo "Reloading launchd"
  launchctl load /Library/LaunchDaemons
  echo "Starting DisOrder server"
  launchctl start uk.org.greenend.rjk.disorder
  server_running=true
  ;;
FreeBSD )
  echo "Installing startup script into /etc/rc.d"
  install -m 555 examples/disorder.rc /etc/rc.d/disorder
  echo "Starting DisOrder server"
  /etc/rc.d/disorder start
  server_running=true
  ;;
Linux )
  echo "Looking for init scripts directory"
  for d in /etc/rc.d /etc; do
    if [ -d $d/init.d ]; then
      RC_D=$d
      break
    fi
  done
  if [ -z "$RC_D" ]; then
    echo "Cannot find your init scripts directory"
  else
    echo "Installing init script into $RC_D/init.d"
    install -m 755 examples/disorder.init $RC_D/init.d/disorder
    echo "Linking init script into $RC_D/rc*.d"
    for n in 2 3 4 5; do
      echo " $RC_D/rc$n.d/S99disorder -> $RC_D/init.d/disorder"
      rm -f $RC_D/rc$n.d/S99disorder
      ln -s $RC_D/init.d/disorder $RC_D/rc$n.d/S99disorder
    done
    for n in 0 1 6; do
      echo " $RC_D/rc$n.d/K01disorder -> $RC_D/init.d/disorder"
      rm -f $RC_D/rc$n.d/K01disorder
      ln -s $RC_D/init.d/disorder $RC_D/rc$n.d/K01disorder
    done
    echo "Starting DisOrder server"
    $RC_D/init.d/disorder start
  fi
  server_running=true
  ;;
* )
  echo
  echo "Sorry, I don't know how to install the server on this platform."
  echo "You will have to do that by hand."
  server_running=false
  ;;
esac

if $server_running; then
  first=true
  sleep 5
  while ! disorder version >/dev/null 2>&1; do
    if $first; then
      echo "Waiting for server startup to complete..."
      first=false
    fi
    sleep 1
  done
  if [ $register = y ]; then
    echo "Creating guest user with 'register' right"
    disorder setup-guest
  else
    echo "Creating guest user without 'register' right"
    disorder setup-guest --no-online-registration
  fi
fi

echo
echo Done
